package com.system.common.service.persion.impl;

import com.system.common.bean.SnowflakeIdWorker;
import com.system.common.constant.BaseEnum;
import com.system.common.constant.RecordStatusConst;
import com.system.common.dao.person.PersonMapper;
import com.system.common.dao.role.PersonRoleMapper;
import com.system.common.entity.person.Person;
import com.system.common.entity.person.PersonExample;
import com.system.common.entity.role.PersonRole;
import com.system.common.entity.role.PersonRoleExample;
import com.system.common.request.BaseReq;
import com.system.common.request.person.AssignRoleReq;
import com.system.common.request.person.LoginReq;
import com.system.common.request.person.SavePersonReq;
import com.system.common.response.BaseResp;
import com.system.common.response.PageResp;
import com.system.common.service.role.RoleService;
import com.system.common.service.persion.PersonService;
import com.system.common.util.EntityUtil;
import com.system.common.util.PageHelperUtil;
import com.system.common.vo.person.LoginVo;
import com.system.common.vo.person.PersonVo;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.encrypt.Encryptors;
import org.springframework.security.crypto.password.Pbkdf2PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;


import java.nio.charset.StandardCharsets;
import java.util.*;

import static com.system.common.constant.BaseEnum.*;

@Service
public class PersonServiceImpl implements PersonService {

    private static final Logger logger = LoggerFactory.getLogger(PersonServiceImpl.class);
    private static final String SALT = "lqwrbkE3vHbhoDV4bfW5ad8vj5qqqAxBlFiBe4pPif6H00=";
    private static final String SALT_HEX = "6c717772626b4533764862686f44563462665735616438766a357171714178426c466942653470506966364830303d";

    @Autowired
    private PersonMapper personMapper;

    @Autowired
    private SnowflakeIdWorker idWorker;

    @Autowired
    private PersonRoleMapper personRoleMapper;

    @Override
    public BaseResp doLogin(LoginReq request) {
        BaseResp resp = new BaseResp();

        Person person = getPersonByName(request.getLoginName());
        if (person == null) {
            resp.setCode(PERSON_LOGIN_ERROR.getCode());
            resp.setMsg(PERSON_LOGIN_ERROR.getMsg());
            return resp;
        }
        Pbkdf2PasswordEncoder passwordEncoder = new Pbkdf2PasswordEncoder();
        if (!passwordEncoder.matches(request.getLoginPassword(), person.getLoginPassword())) {
            resp.setCode(PERSON_LOGIN_ERROR.getCode());
            resp.setMsg(PERSON_LOGIN_ERROR.getMsg());
            return resp;
        }
        long timeout = System.currentTimeMillis()+2*60*60*1000;
        String tokenSource = person.getId()+"-"+timeout;
        byte[] encrypt = Encryptors.stronger(person.getLoginPassword(), SALT_HEX).encrypt(tokenSource.getBytes(StandardCharsets.UTF_8));
        String token = new String(Base64.getEncoder().encode(encrypt),StandardCharsets.UTF_8);
        LoginVo data = new LoginVo();
        data.setId(person.getId());
        data.setToken(token);
        data.setLoginName(person.getLoginName());
        data.setState(person.getState());
        resp.setCode(BaseEnum.SUCCESS.getCode());
        resp.setData(data);
        return resp;
    }


    @Override
    public BaseResp savePerson(SavePersonReq req) {
        if (req.getId() == null || req.getId() == 0) {
            return addPerson(req);
        } else {
            //登陆名一旦创建就不能修改，只能改其状态
            return updatePerson(req);
        }

    }

    @Override
    public Person getPersonByName(String name) {
        PersonExample example = new PersonExample();
        example.createCriteria()
                .andLoginNameEqualTo(name)
                .andStateEqualTo(RecordStatusConst.ENABLE);
        Person user = EntityUtil.getFirst(personMapper.selectByExample(example));
        return user;
    }

    @Override
    public Person getPersonById(Long id) {
        PersonExample example = new PersonExample();
        example.createCriteria()
                .andIdEqualTo(id)
                .andStateEqualTo(RecordStatusConst.ENABLE);
        Person user = EntityUtil.getFirst(personMapper.selectByExample(example));
        return user;
    }

    @Override
    public Person getPersonByToken(String token,Long id) {
        if(StringUtils.isBlank(token) || id == null){
            return null;
        }
        Person person = getPersonById(id);
        if(person==null){
            return null;
        }
        byte[] encrypt = Base64.getDecoder().decode(token.getBytes(StandardCharsets.UTF_8));
        String tokenSource = new String(Encryptors.stronger(person.getLoginPassword(), SALT_HEX).decrypt(encrypt),StandardCharsets.UTF_8);
        if(StringUtils.isBlank(tokenSource)){
            return null;
        }
        String[] data = tokenSource.split("-");
        if(data==null || data.length!=2){
            return null;
        }
        try {
            long timeout = Long.parseLong(data[1]);
            if(timeout<System.currentTimeMillis()){
                logger.info("token失效,timeout:{},token:{}",data[1],token);
                return null;
            }
            if(!Objects.equals(person.getId().toString(),data[0])){
                logger.info("token非法,id:{},dbId:{}",data[0],person.getId().toString());
                return null;
            }
            return person;
        }catch (Exception e){
            logger.info("登陆时长转数字异常,timeout:"+data[1],e);
            return null;
        }
    }

    @Override
    public PageResp search(SavePersonReq req) {
        PageResp resp = new PageResp();
        PersonExample example = new PersonExample();
        PersonExample.Criteria criteria = example.createCriteria();
        if(StringUtils.isNoneBlank(req.getLoginName())){
            criteria.andLoginNameLike("%"+req.getLoginName()+"%");
        }else{
            req.setLoginName(null);
        }
        if(req.getId()!=null && req.getId()!=0){
            criteria.andIdEqualTo(req.getId());
        }
        if(req.getState()!=null){
            criteria.andStateEqualTo(req.getState());
        }
        Long totalRecord = personMapper.countByExample(example);
        if(totalRecord==null || totalRecord==0){
            return PageHelperUtil.getDefaultPageHelper();
        }
        int pageSize = PageHelperUtil.getDefaultPageSize(req.getPageSize());
        Integer offset = PageHelperUtil.getOffset(Integer.valueOf(totalRecord.toString()),
                PageHelperUtil.getDefaultCurrentPage(req.getCurrentPage()),pageSize);
        List<PersonVo> data = personMapper.selectByPage(req,pageSize, offset);
        resp.setCode(SUCCESS.getCode());
        resp.setData(data);
        resp.setTotalRecord(totalRecord);
        return resp;
    }

    @Override
    public BaseResp delPerson(BaseReq req) {
        BaseResp resp = new BaseResp();
        if(req.getId()==null || req.getId()==0){
            resp.setCode(PERSON_DEL_ARGS_ERROR.getCode());
            resp.setMsg(PERSON_DEL_ARGS_ERROR.getMsg());
            return resp;
        }

        Person person = getPersonById(req.getId());
        if (person == null) {
            resp.setCode(PERSON_SAVE_ARGS_ERROR.getCode());
            resp.setMsg("查询不到用户");
            return resp;
        }
        PersonExample example = new PersonExample();
        example.createCriteria()
                .andIdEqualTo(person.getId());
        personMapper.deleteByExample(example);
        resp.setCode(BaseEnum.SUCCESS.getCode());
        resp.setMsg(BaseEnum.SUCCESS.getMsg());
        return resp;
    }

    @Override
    @Transactional
    public BaseResp assignRole(AssignRoleReq req) {
        BaseResp resp = new BaseResp();
        if(req.getId()==null || req.getId()==0){
            resp.setCode(PERSON_DEL_ARGS_ERROR.getCode());
            resp.setMsg(PERSON_DEL_ARGS_ERROR.getMsg());
            return resp;
        }
        Long[] roleIdArr = req.getRole();
        if(roleIdArr==null || roleIdArr.length==0){
            resp.setCode(ARGS_ERROR.getCode());
            resp.setMsg(ARGS_ERROR.getMsg());
            return resp;
        }

        // 先删掉之前角色
        PersonRoleExample example = new PersonRoleExample();
        example.createCriteria()
                .andPersonIdEqualTo(req.getId());
        personRoleMapper.deleteByExample(example);

        Date now = new Date();
        for(int i=0;i<roleIdArr.length;i++){
            PersonRole personRole = new PersonRole();
            personRole.setId(idWorker.nextId());
            personRole.setRoleId(roleIdArr[i]);
            personRole.setPersonId(req.getId());
            personRole.setCreateTime(now);
            personRoleMapper.insertSelective(personRole);
        }
        resp.setCode(SUCCESS.getCode());
        resp.setMsg(SUCCESS.getMsg());
        return resp;
    }

    private BaseResp addPerson(SavePersonReq req) {
        BaseResp resp = new BaseResp();
        if (StringUtils.isBlank(req.getLoginName()) || StringUtils.isBlank(req.getLoginPassword())) {
            resp.setCode(PERSON_SAVE_ARGS_ERROR.getCode());
            resp.setMsg(PERSON_SAVE_ARGS_ERROR.getMsg());
            return resp;
        }

        Person person = getRealPersonByName(req.getLoginName());
        if (person != null) {
            resp.setCode(PERSON_SAVE_ARGS_ERROR.getCode());
            resp.setMsg("登陆名已经存在");
            return resp;
        }
        person = new Person();
        person.setId(idWorker.nextId());
        person.setLoginName(req.getLoginName());
        Pbkdf2PasswordEncoder passwordEncoder = new Pbkdf2PasswordEncoder();
        person.setLoginPassword(passwordEncoder.encode(req.getLoginPassword()));
        person.setState(RecordStatusConst.ENABLE);
        person.setCreateTime(new Date());
        personMapper.insertSelective(person);
        resp.setCode(BaseEnum.SUCCESS.getCode());
        resp.setMsg(BaseEnum.SUCCESS.getMsg());
        return resp;
    }

    private BaseResp updatePerson(SavePersonReq req) {
        BaseResp resp = new BaseResp();
        if(StringUtils.isBlank(req.getLoginName())){
            resp.setCode(PERSON_SAVE_ARGS_ERROR.getCode());
            resp.setMsg(PERSON_SAVE_ARGS_ERROR.getMsg());
            return resp;
        }
        Person person = getRealPersonById(req.getId());
        if (person == null) {
            resp.setCode(PERSON_SAVE_ARGS_ERROR.getCode());
            resp.setMsg("查询不到用户");
            return resp;
        }

        Person loginName = getRealPersonByName(req.getLoginName());
        if(loginName!=null && !Objects.equals(person.getId(),loginName.getId())){
            resp.setCode(PERSON_SAVE_ARGS_ERROR.getCode());
            resp.setMsg("登陆名已存在");
            return resp;
        }
        PersonExample example = new PersonExample();
        example.createCriteria()
                .andIdEqualTo(person.getId());

        person.setLoginName(req.getLoginName());
        person.setState(req.getState());
        person.setEditTime(new Date());
        personMapper.updateByExampleSelective(person, example);
        resp.setCode(BaseEnum.SUCCESS.getCode());
        resp.setMsg(BaseEnum.SUCCESS.getMsg());
        return resp;
    }

    private Person getRealPersonById(Long id){
        PersonExample example = new PersonExample();
        example.createCriteria()
                .andIdEqualTo(id);
        Person user = EntityUtil.getFirst(personMapper.selectByExample(example));
        return user;
    }

    private Person getRealPersonByName(String name) {
        PersonExample example = new PersonExample();
        example.createCriteria()
                .andLoginNameEqualTo(name);
        Person user = EntityUtil.getFirst(personMapper.selectByExample(example));
        return user;
    }
}
